

#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cstring>


// 调用： ./TcpClient Server-IP Server-Port 
int main(int argc, char* argv[])
{
    if (argc != 3)
    {
        std::cerr << "Usage: " << argv[0] << " Server-IP Server-Port" << std::endl;
        exit(0);
    }
    std::string ServerIP = argv[1];
    in_port_t ServerPort = std::stoi(argv[2]);

    // 创建套接字 
    int sockfd = ::socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0)
    {
        std::cerr << "Create socket error, errno: " << errno << " -> " << strerror(errno) << std::endl;
        exit(1);
    }

    // 客户端依然不需要显示绑定，但是 OS 会自动进行隐式的绑定，因为要网络通信，必定需要 IP 和 Port（随机） 
    // 客户端也不需要进行监听，因为不会有其他客户端连接自己的客户端，服务器也是自己发出的请求！ 
    // 所以客户端可以直接向服务端发起连接 
    // 而 bind 会在连接成功之前进行 
    struct sockaddr_in server;
    memset(&server, 0, sizeof server);
    server.sin_family = AF_INET;
    server.sin_port = htons(ServerPort);
    ::inet_pton(AF_INET, ServerIP.c_str(), &server.sin_addr);

    int n = connect(sockfd, (struct sockaddr*)&server, sizeof server);
    if (n < 0)
    {
        std::cerr << "Connect error, errno: " << errno << " -> " << strerror(errno) << std::endl;
        exit(2);
    }

    while (true)
    {
        std::string msg;
        std::cout << "Enter # ";
        std::getline(std::cin, msg);

        write(sockfd, msg.c_str(), msg.size());

        char echo_buffer[1024];
        n = read(sockfd, echo_buffer, (sizeof echo_buffer) -1);
        if (n > 0)
        {
            echo_buffer[n] = 0;
            std::cout << echo_buffer << std::endl;
        }
        else 
        {
            break;
        }
    }

    ::close(sockfd);
    return 0;
}

